package cart_logic

import (
	"context"
	"encoding/json"
	"fmt"
	"strings"
	"time"
	"wx-uniapp-go/internal/repository/dto"
	"wx-uniapp-go/internal/repository/models"
	"wx-uniapp-go/third_party/oss"
	"wx-uniapp-go/third_party/rediscli"
)

const (
	// Redis key前缀
	cartListKeyPrefix  = "cart:list:"     // 购物车列表key前缀
	cartCountKeyPrefix = "cart:count:"    // 购物车数量key前缀
	cacheExpiration    = 30 * time.Minute // 缓存过期时间
)

type CartLogic struct {
	Ctx context.Context
}

func NewCartLogic(ctx context.Context) *CartLogic {
	return &CartLogic{Ctx: ctx}
}

// 获取购物车列表缓存key
func getCartListKey(userId int64) string {
	return fmt.Sprintf("%s%d", cartListKeyPrefix, userId)
}

// 获取购物车数量缓存key
func getCartCountKey(userId int64) string {
	return fmt.Sprintf("%s%d", cartCountKeyPrefix, userId)
}

// 清除购物车缓存
func (l *CartLogic) clearCartCache(userId int64) {
	rediscli.Default().Del(l.Ctx, getCartListKey(userId))
	rediscli.Default().Del(l.Ctx, getCartCountKey(userId))
}

// GetCartCount 获取购物车商品总数
func (l *CartLogic) GetCartCount(userId int64) (*dto.CartCountResp, error) {
	// 尝试从缓存获取
	key := getCartCountKey(userId)
	count, err := rediscli.Default().Get(l.Ctx, key)
	if err == nil && count != "" {
		var countInt int
		err = json.Unmarshal([]byte(count), &countInt)
		if err == nil {
			return &dto.CartCountResp{Count: countInt}, nil
		}
	}

	// 缓存未命中,查询数据库
	var total int64
	total, err = models.Count(l.Ctx, &models.Cart{}, "user_id = ? AND status = ?", userId, 1)
	if err != nil {
		return nil, err
	}

	// 更新缓存
	countResp := &dto.CartCountResp{Count: int(total)}
	rediscli.Default().SetBytes(l.Ctx, key, countResp, cacheExpiration)

	return countResp, nil
}

// GetCartList 获取购物车列表
func (l *CartLogic) GetCartList(userId int64) (*dto.CartListResp, error) {
	// 尝试从缓存获取
	key := getCartListKey(userId)
	data, err := rediscli.Default().Get(l.Ctx, key)
	if err == nil && data != "" {
		var resp dto.CartListResp
		err = json.Unmarshal([]byte(data), &resp)
		if err == nil {
			return &resp, nil
		}
	}

	// 缓存未命中,查询数据库
	var carts []*models.Cart
	err = models.Find(l.Ctx, &carts, "user_id = ? AND status = ?", userId, 1)
	if err != nil {
		return nil, err
	}

	if len(carts) == 0 {
		resp := &dto.CartListResp{
			List:          make([]dto.CartItem, 0),
			TotalAmount:   0,
			FreightAmount: 0,
			PayAmount:     0,
		}
		// 更新缓存
		rediscli.Default().SetBytes(l.Ctx, key, resp, cacheExpiration)
		return resp, nil
	}

	// 获取商品和SKU信息
	productIds := make([]string, 0, len(carts))
	skuIds := make([]string, 0, len(carts))
	for _, cart := range carts {
		productIds = append(productIds, cart.ProductId)
		skuIds = append(skuIds, cart.SkuId)
	}

	products, err := models.ProductFindByIds(l.Ctx, productIds)
	if err != nil {
		return nil, err
	}
	skus, err := models.SkuFindByIds(l.Ctx, skuIds)
	if err != nil {
		return nil, err
	}

	// 构建映射
	productMap := make(map[string]*models.Product)
	for _, product := range products {
		productMap[product.Id] = product
	}
	skuMap := make(map[string]*models.Sku)
	for _, sku := range skus {
		skuMap[sku.Id] = sku
	}

	// 构建响应
	list := make([]dto.CartItem, 0, len(carts))
	var totalAmount, payAmount int64
	for _, cart := range carts {
		product := productMap[cart.ProductId]
		sku := skuMap[cart.SkuId]
		if product == nil || sku == nil {
			continue
		}

		stockStatus := 0
		if sku.Stock >= cart.Quantity {
			stockStatus = 1
		}

		item := dto.CartItem{
			Id:          cart.Id,
			ProductId:   cart.ProductId,
			SkuId:       cart.SkuId,
			ProductName: product.Title,
			SkuName:     sku.Name,
			Image:       oss.Cli.JoinPath(product.Cover),
			Price:       product.Price,
			OriginPrice: product.OriginPrice,
			Quantity:    cart.Quantity,
			Selected:    cart.Selected,
			Stock:       sku.Stock,
			SalesVolume: product.SalesVolume,
			SkuList:     product.SkuList,
			StockStatus: stockStatus,
		}
		list = append(list, item)

		if cart.Selected == 1 {
			totalAmount += product.Price * int64(cart.Quantity)
			payAmount += product.OriginPrice * int64(cart.Quantity)
		}
	}

	// 计算运费和实付金额
	freightAmount := int64(0)
	if totalAmount < 99 {
		freightAmount = 10
	}
	payAmount = payAmount + freightAmount

	resp := &dto.CartListResp{
		List:          list,
		TotalAmount:   totalAmount,
		FreightAmount: freightAmount,
		PayAmount:     payAmount,
	}

	// 更新缓存
	rediscli.Default().SetBytes(l.Ctx, key, resp, cacheExpiration)

	return resp, nil
}

// AddCart 添加购物车
func (l *CartLogic) AddCart(userId int64, req *dto.CartAddReq) error {
	// 检查商品和SKU是否存在
	product, err := models.Get(l.Ctx, &models.Product{}, "id = ? AND status = ?", req.ProductId, models.ProductStatusOnSale)
	if err != nil {
		return err
	}
	if !product {
		return fmt.Errorf("商品不存在")
	}

	sku, err := models.SkuFindOne(l.Ctx, req.SkuId)
	if err != nil {
		return err
	}
	if sku == nil {
		return fmt.Errorf("商品规格不存在")
	}

	// 检查库存
	if sku.Stock < req.Quantity {
		return fmt.Errorf("商品库存不足")
	}

	// 检查是否已存在相同商品
	var cart models.Cart
	exists, err := models.Get(l.Ctx, &cart, "user_id = ? AND product_id = ? AND sku_id = ? AND status = ?",
		userId, req.ProductId, req.SkuId, 1)
	if err != nil {
		return err
	}

	if exists {
		// 更新数量
		cart.Quantity = req.Quantity
		if cart.Quantity > sku.Stock {
			return fmt.Errorf("商品库存不足")
		}
		err = models.Update(l.Ctx, fmt.Sprintf("id = %d", cart.Id), cart)
		if err != nil {
			return err
		}
	} else {
		// 新增购物车
		cart = models.Cart{
			UserId:    userId,
			ProductId: req.ProductId,
			SkuId:     req.SkuId,
			Quantity:  req.Quantity,
			Selected:  1,
			Status:    1,
		}
		_, err = models.Insert(l.Ctx, &cart)
		if err != nil {
			return err
		}
	}

	// 清除缓存
	l.clearCartCache(userId)
	return nil
}

// UpdateCart 更新购物车
func (l *CartLogic) UpdateCart(userId int64, req *dto.CartUpdateReq) error {
	// 获取购物车商品
	cart, err := models.CartFindOne(l.Ctx, req.Id)
	if err != nil {
		return err
	}
	if cart == nil || cart.UserId != userId || cart.Status != 1 {
		return fmt.Errorf("购物车商品不存在")
	}

	// 更新数量
	if req.Quantity > 0 {
		// 检查库存
		sku, err := models.SkuFindOne(l.Ctx, cart.SkuId)
		if err != nil {
			return err
		}
		if sku == nil {
			return fmt.Errorf("商品规格不存在")
		}
		if sku.Stock < req.Quantity {
			return fmt.Errorf("商品库存不足")
		}
		cart.Quantity = req.Quantity
	}

	// 更新选中状态
	if req.Selected >= 0 {
		cart.Selected = req.Selected
	}

	err = models.Update(l.Ctx, fmt.Sprintf("id = %d", cart.Id), cart)

	// 清除缓存
	l.clearCartCache(userId)
	return err
}

// DeleteCart 删除购物车
func (l *CartLogic) DeleteCart(userId int64, req *dto.CartDeleteReq) error {
	err := models.CartBatchDelete(l.Ctx, userId, req.Ids)

	// 清除缓存
	l.clearCartCache(userId)
	return err
}

// CreateOrder 创建订单
func (l *CartLogic) CreateOrder(userId int64, req *dto.CreateOrderReq) (*dto.OrderDetailResp, error) {
	// 获取收货地址
	var address models.UserAddress
	exists, err := models.Get(l.Ctx, &address, "id = ? AND user_id = ? AND status = ?",
		req.AddressId, userId, models.AddressStatusNormal)
	if err != nil {
		return nil, err
	}
	if !exists {
		return nil, fmt.Errorf("收货地址不存在")
	}

	// 获取购物车选中商品
	var carts []*models.Cart
	err = models.Find(l.Ctx, &carts, "user_id = ? AND status = ? AND selected = ?",
		userId, 1, 1)
	if err != nil {
		return nil, err
	}
	if len(carts) == 0 {
		return nil, fmt.Errorf("请选择要购买的商品")
	}

	// 获取商品和SKU信息
	productIds := make([]string, 0, len(carts))
	skuIds := make([]string, 0, len(carts))
	for _, cart := range carts {
		productIds = append(productIds, cart.ProductId)
		skuIds = append(skuIds, cart.SkuId)
	}

	products, err := models.ProductFindByIds(l.Ctx, productIds)
	if err != nil {
		return nil, err
	}
	skus, err := models.SkuFindByIds(l.Ctx, skuIds)
	if err != nil {
		return nil, err
	}

	// 构建映射
	productMap := make(map[string]*models.Product)
	for _, product := range products {
		productMap[product.Id] = product
	}
	skuMap := make(map[string]*models.Sku)
	for _, sku := range skus {
		skuMap[sku.Id] = sku
	}

	// 检查库存并计算金额
	var totalAmount float64
	orderItems := make([]*models.OrderItem, 0, len(carts))
	for _, cart := range carts {
		product := productMap[cart.ProductId]
		sku := skuMap[cart.SkuId]
		if product == nil || sku == nil {
			return nil, fmt.Errorf("商品不存在")
		}

		// 检查库存
		if sku.Stock < cart.Quantity {
			return nil, fmt.Errorf("商品[%s]库存不足", product.Title)
		}

		// 计算金额
		itemAmount := sku.Price * float64(cart.Quantity)
		totalAmount += itemAmount

		// 构建订单商品
		orderItems = append(orderItems, &models.OrderItem{
			ProductId:    cart.ProductId,
			SkuId:        cart.SkuId,
			ProductName:  product.Title,
			SkuName:      sku.Name,
			ProductImage: product.Cover,
			Quantity:     cart.Quantity,
			Price:        sku.Price,
			TotalAmount:  itemAmount,
		})
	}

	// 计算运费和实付金额
	freightAmount := float64(0)
	if totalAmount < 99 {
		freightAmount = 10
	}
	payAmount := totalAmount + freightAmount

	// 使用优惠券
	var couponDiscount float64
	var userCoupon *models.UserCoupon
	if req.CouponId > 0 {
		// 获取优惠券信息
		userCoupon = &models.UserCoupon{}
		exists, err := models.Get(l.Ctx, userCoupon,
			"id = ? AND user_id = ? AND status = ? AND valid_end > ?",
			req.CouponId, userId, models.CouponStatusUnused, time.Now())
		if err != nil {
			return nil, err
		}
		if !exists {
			return nil, fmt.Errorf("优惠券不存在或已过期")
		}

		// 检查最低使用金额
		if totalAmount < float64(userCoupon.MinAmount) {
			return nil, fmt.Errorf("订单金额未达到优惠券使用条件")
		}

		// 计算优惠金额
		switch userCoupon.Type {
		case models.CouponTypeAmount:
			// 满减券
			couponDiscount = float64(userCoupon.Value)
		case models.CouponTypeDiscount:
			// 折扣券，value为折扣率，例如80表示8折
			couponDiscount = totalAmount * (100 - float64(userCoupon.Value)) / 100
		}

		// 优惠金额不能超过订单金额
		if couponDiscount > totalAmount {
			couponDiscount = totalAmount
		}

		// 更新实付金额
		payAmount = totalAmount + freightAmount - couponDiscount
	}

	// 生成订单号
	orderNo := fmt.Sprintf("%s%d", time.Now().Format("20060102150405"), userId)

	// 创建订单
	order := &models.Order{
		OrderNo:       orderNo,
		UserId:        userId,
		TotalAmount:   totalAmount,
		PayAmount:     payAmount,
		FreightAmount: freightAmount,
		Status:        0,
		AddressId:     address.Id,
		ReceiverName:  address.Name,
		ReceiverPhone: address.Mobile,
		ReceiverAddr:  fmt.Sprintf("%s%s%s%s%s", address.ProvinceName, address.CityName, address.DistrictName, address.Address, address.HouseNumber),
		Note:          req.Note,
	}

	// 开启事务
	session := models.BeginTransaction(l.Ctx)

	if err != nil {
		return nil, err
	}

	// 插入订单
	_, err = models.Insert(session, order)
	if err != nil {
		return nil, err
	}

	// 插入订单商品
	for _, item := range orderItems {
		item.OrderId = order.Id
		_, err = models.Insert(session, item)
		if err != nil {
			return nil, err
		}

		// 扣减库存
		_, err = models.Exec(session,
			"UPDATE sku SET stock = stock - ? WHERE id = ? AND stock >= ?",
			item.Quantity, item.SkuId, item.Quantity)
		if err != nil {
			return nil, err
		}
	}

	// 使用优惠券
	if userCoupon != nil {
		// 更新优惠券状态
		userCoupon.Status = models.CouponStatusUsed
		userCoupon.UseTime = time.Now()
		err = models.Update(session, fmt.Sprintf("id = %d", userCoupon.Id), userCoupon)
		if err != nil {
			return nil, err
		}

		// 记录优惠券使用日志
		couponLog := &models.CouponLog{
			UserId:   userId,
			CouponId: userCoupon.Id,
			Type:     models.CouponLogTypeUse,
			OrderId:  order.Id,
			Amount:   int64(totalAmount * 100),    // 转换为分
			Discount: int64(couponDiscount * 100), // 转换为分
			Remark:   "下单使用优惠券",
		}
		_, err = models.Insert(session, couponLog)
		if err != nil {
			return nil, err
		}
	}

	// 清空购物车
	where := fmt.Sprintf("user_id = %d AND status = 1 AND selected = 1", userId)
	err = models.Delete(l.Ctx, &models.Cart{}, where)
	if err != nil {
		return nil, err
	}
	models.CloseTransaction(l.Ctx, err)

	// 构建响应
	items := make([]dto.OrderItem, len(orderItems))
	for i, item := range orderItems {
		items[i] = dto.OrderItem{
			ProductId:    item.ProductId,
			SkuId:        item.SkuId,
			ProductName:  item.ProductName,
			SkuName:      item.SkuName,
			ProductImage: oss.Cli.JoinPath(item.ProductImage),
			Quantity:     item.Quantity,
			Price:        item.Price,
			TotalAmount:  item.TotalAmount,
		}
	}

	return &dto.OrderDetailResp{
		Id:            order.Id,
		OrderNo:       order.OrderNo,
		TotalAmount:   order.TotalAmount,
		PayAmount:     order.PayAmount,
		FreightAmount: order.FreightAmount,
		Status:        order.Status,
		ReceiverName:  order.ReceiverName,
		ReceiverPhone: order.ReceiverPhone,
		ReceiverAddr:  order.ReceiverAddr,
		Note:          order.Note,
		Items:         items,
		CreateTime:    order.CreateTime.Format("2006-01-02 15:04:05"),
	}, nil
}

// BatchUpdateSelected 批量更新选中状态
func (l *CartLogic) BatchUpdateSelected(userId int64, req *dto.CartBatchUpdateSelectedReq) error {
	err := models.CartBatchSelected(l.Ctx, userId, req.Selected, req.Ids)
	if err != nil {
		return err
	}
	// 清除缓存
	l.clearCartCache(userId)
	return nil
}

// ClearCart 清空购物车
func (l *CartLogic) ClearCart(userId int64) error {
	err := models.Delete(l.Ctx, &models.Cart{}, fmt.Sprintf("user_id = %d AND status = 1", userId))
	if err != nil {
		return err
	}

	// 清除缓存
	l.clearCartCache(userId)
	return nil
}

// GetCartStock 获取购物车商品库存状态
func (l *CartLogic) GetCartStock(userId int64) (*dto.CartStockResp, error) {
	// 获取购物车商品
	var carts []*models.Cart
	err := models.Find(l.Ctx, &carts, "user_id = ? AND status = ?", userId, 1)
	if err != nil {
		return nil, err
	}

	if len(carts) == 0 {
		return &dto.CartStockResp{List: make([]dto.CartStockItem, 0)}, nil
	}

	// 获取SKU信息
	skuIds := make([]string, 0, len(carts))
	for _, cart := range carts {
		skuIds = append(skuIds, cart.SkuId)
	}

	skus, err := models.SkuFindByIds(l.Ctx, skuIds)
	if err != nil {
		return nil, err
	}

	// 构建SKU映射
	skuMap := make(map[string]*models.Sku)
	for _, sku := range skus {
		skuMap[sku.Id] = sku
	}

	// 构建响应
	list := make([]dto.CartStockItem, 0, len(carts))
	for _, cart := range carts {
		sku := skuMap[cart.SkuId]
		if sku == nil {
			continue
		}

		stockStatus := 0
		if sku.Stock >= cart.Quantity {
			stockStatus = 1
		}

		item := dto.CartStockItem{
			Id:          cart.Id,
			ProductId:   cart.ProductId,
			SkuId:       cart.SkuId,
			Stock:       sku.Stock,
			StockStatus: stockStatus,
		}
		list = append(list, item)
	}

	return &dto.CartStockResp{List: list}, nil
}

// buildInParams 构建IN查询参数
func buildInParams(ids []int64) string {
	params := make([]string, len(ids))
	for i := range ids {
		params[i] = "?"
	}
	return strings.Join(params, ",")
}

// buildInParams 构建IN查询参数
func buildInParamsStr(ids []string) string {
	params := make([]string, len(ids))
	for i := range ids {
		params[i] = "?"
	}
	return strings.Join(params, ",")
}
